package com.happymmall.util;

import io.jsonwebtoken.*;
import io.jsonwebtoken.security.Keys;

import javax.crypto.SecretKey;
import java.nio.charset.StandardCharsets;
import java.util.Date;
import java.util.Map;
import java.util.function.Function;

public class JwtUtils {


    // 注意：HS256算法要求密钥至少32个字符
    private static final String SECRET_KEY = "this-is-a-test-secret-key-with-32-or-more-chars";

    // 默认过期时间（毫秒），2小时
    private static final long DEFAULT_EXPIRATION = 7200000;

    static {
        // 验证密钥长度
        if (SECRET_KEY.getBytes(StandardCharsets.UTF_8).length < 32) {
            throw new IllegalArgumentException("JWT密钥长度不足，HS256算法至少需要32个字符");
        }
    }

    /**
     * 生成JWT令牌（使用默认过期时间，不添加任何自定义声明）
     */
    public static String generateToken() {
        return generateToken(Map.of(), DEFAULT_EXPIRATION);
    }

    /**
     * 生成JWT令牌（使用默认过期时间）
     */
    public static String generateToken(Map<String, Object> claims) {
        return generateToken(claims, DEFAULT_EXPIRATION);
    }

    /**
     * 生成JWT令牌（支持自定义过期时间）
     */
    public static String generateToken(Map<String, Object> claims, long expiration) {
        SecretKey key = Keys.hmacShaKeyFor(SECRET_KEY.getBytes(StandardCharsets.UTF_8));

        return Jwts.builder()
                .signWith(key, SignatureAlgorithm.HS256)
                .addClaims(claims)  // 使用addClaim添加自定义声明
                .setIssuedAt(new Date())
                .setExpiration(new Date(System.currentTimeMillis() + expiration))
                .compact();
    }

    /**
     * 解析JWT令牌并获取所有声明
     */
    public static Claims extractAllClaims(String token) {
        SecretKey key = Keys.hmacShaKeyFor(SECRET_KEY.getBytes(StandardCharsets.UTF_8));

        try {
            return Jwts.parserBuilder()
                    .setSigningKey(key)
                    .build()
                    .parseClaimsJws(token)
                    .getBody();
        } catch (ExpiredJwtException e) {
            throw new JwtException("令牌已过期", e);
        } catch (UnsupportedJwtException e) {
            throw new JwtException("不支持的令牌格式", e);
        } catch (MalformedJwtException e) {
            throw new JwtException("令牌格式错误", e);
        } catch (SignatureException e) {
            throw new JwtException("签名验证失败", e);
        } catch (IllegalArgumentException e) {
            throw new JwtException("令牌参数错误", e);
        }
    }

    /**
     * 从令牌中获取指定声明
     */
    public static <T> T extractClaim(String token, Function<Claims, T> claimsResolver) {
        final Claims claims = extractAllClaims(token);
        return claimsResolver.apply(claims);
    }

    /**
     * 验证令牌是否有效
     */
    public static boolean isValidToken(String token) {
        try {
            extractAllClaims(token);
            return !isTokenExpired(token);
        } catch (JwtException e) {
            return false;
        }
    }

    /**
     * 检查令牌是否已过期
     */
    public static boolean isTokenExpired(String token) {
        Date expiration = extractClaim(token, Claims::getExpiration);
        return expiration.before(new Date());
    }
}

